package tr.richfacesext.components.captcha.core;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;

import tr.richfacesext.components.captcha.CaptchaConstants;

/**
 * 
 * @author mert
 *
 */
public class CaptchaImageImpl implements CaptchaImage {

    private int maxX;
    private int maxY;
    private int letterWidth;
    private int maxLength;
    private int drawLines;
    private int drawBoxes;
    private double imgSkew;
    private boolean invertColors;
    
    
	public CaptchaImageImpl(int letterWidth, int maxLength, int imgHeight, int drawLines, int drawBoxes, double imgSkew, boolean invertColors) {
		this.letterWidth = letterWidth;
		this.maxLength = maxLength;
		this.drawLines = drawLines;	
		this.drawBoxes = drawBoxes;
		this.imgSkew = imgSkew;
		this.invertColors = invertColors;
		
		maxX = letterWidth * maxLength;
		maxY = imgHeight;
	}
	
	public BufferedImage skewImage(String securityChars)  {
        BufferedImage outImage = new BufferedImage(maxX, maxY, 1);
        Graphics2D g2d = outImage.createGraphics();
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, maxX, maxY);
        for(int i = 0; i < drawBoxes; i++)
            paintBoxes(g2d);

        g2d.setColor(Color.BLACK);
        g2d.drawRect(0, 0, maxX - 1, maxY - 1);
        AffineTransform affineTransform = new AffineTransform();
        for(int i = 0; i < maxLength; i++)  {
            double angle = 0.0D;
            if(Math.random() * 2D > 1.0D)
                angle = Math.random() * imgSkew;
            else
                angle = Math.random() * -imgSkew;
            affineTransform.rotate(angle, letterWidth * i + letterWidth / 2, maxY / 2);
            g2d.setTransform(affineTransform);
            setRandomFont(g2d);
            setRandomFGColor(g2d);
            g2d.drawString(securityChars.substring(i, i + 1), i * letterWidth + 3, 28 + (int)(Math.random() * 6D));
            affineTransform.rotate(-angle, letterWidth * i + letterWidth / 2, maxY / 2);
        }

        for(int i = 0; i < drawLines; i++)       {
            g2d.setXORMode(Color.RED);
            setRandomBGColor(g2d);
            g2d.setStroke(new BasicStroke(4F));
            int y1 = (int)(Math.random() * (double) maxY);
            g2d.drawLine(0, y1, maxX, y1);
        }
        
        if (invertColors)
        	return invertColors(outImage);
        
        return outImage;
    }

    public BufferedImage invertColors(BufferedImage image) {
        int w = image.getWidth();
        int h = image.getHeight();
        BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        RescaleOp op = new RescaleOp(-1, 255, null);
        return op.filter(image, newImage);
    }
	
    private void paintBoxes(Graphics2D g2d)   {
        setRandomBGColor(g2d);
        g2d.fillRect(getRandomX(), getRandomY(), getRandomX(), getRandomY());
    }

    private int getRandomX()   {
        return (int)(Math.random() * (double) maxX);
    }

    private int getRandomY()   {
        return (int)(Math.random() * (double) maxY);
    }

    private void setRandomFont(Graphics2D g2d)   {
        Font font = new Font("dialog", 1, 33);
        g2d.setFont(font);
    }

    private void setRandomFGColor(Graphics2D g2d)   {
        int colorId = (int)(Math.random() * (double) CaptchaConstants.RANDOM_FG_COLORS.length);
        g2d.setColor(CaptchaConstants.RANDOM_FG_COLORS[colorId]);
    }

    private void setRandomBGColor(Graphics2D g2d)   {
        int colorId = (int)(Math.random() * (double) CaptchaConstants.RANDOM_BG_COLORS.length);
        g2d.setColor(CaptchaConstants.RANDOM_BG_COLORS[colorId]);
    }
}